#include <math.h>
#include <allegro.h>
#include <string.h>
#include <stdio.h>
#include "databank.h"
#include "player.h"
#include "sprite.h"
#include "shot.h"

Shot::Shot(DataBank *d, ShotType t, double pos[2], double vel[2])
{
    data = d;
    type = t;
    killMe = 0;
    pic = NULL;
    g = data->getPhysicsModule()->addGravitated(pos,vel, 1.0, SHOT, this);

    memset(arg,0,sizeof(arg));
    memset(flag,0,sizeof(flag));

    life = 100;

    // Default parameters
    doIdle = doNothing;
    doInteraction = doIdleInteraction;

    // Add new shottype pointers here when needed
    switch(type) {
        case SHOT_GUN:
            pic = d->sprites->get_shot("gun.bmp");
            doBackgroundCollision = Gun::doBackgroundCollision;
            doPlayerCollision = Gun::doPlayerCollision;
            break;
        case SHOT_MISSILE:
            doBackgroundCollision = Missile::doBackgroundCollision;
            doPlayerCollision = Missile::doPlayerCollision;
            break;
        case SHOT_LASER:
            doBackgroundCollision = Laser::doBackgroundCollision;
            doIdle = Laser::doIdle;
            doPlayerCollision = Laser::doPlayerCollision;
            break;
        case SHOT_CLUSTER:
            pic = d->sprites->get_shot("cluster.bmp");
            doBackgroundCollision = Cluster::doBackgroundCollision;
            doPlayerCollision = Cluster::doPlayerCollision;
            break;
        case SHOT_BLACKHOLE:
            doBackgroundCollision = BlackHole::doBackgroundCollision;
            doPlayerCollision = BlackHole::doPlayerCollision;
            break;
        case SHOT_BADGER:
            pic = d->sprites->get_shot("badger.bmp");
            doBackgroundCollision = Badger::doBackgroundCollision;
            doIdle = Badger::doIdle;
            doPlayerCollision = Badger::doPlayerCollision;
            break;
        case SHOT_PLANETMAKER:
            doBackgroundCollision = PlanetMaker::doBackgroundCollision;
            doIdle = PlanetMaker::doIdle;
            doInteraction = PlanetMaker::doInteraction;
            doPlayerCollision = PlanetMaker::doPlayerCollision;
            break;
        case SHOT_CARPET:
            doBackgroundCollision = Carpet::doBackgroundCollision;
            doPlayerCollision = Carpet::doPlayerCollision;
            break;
        case SHOT_PANZERSCHRECK:
            pic = d->sprites->get_shot("panzerschrek.bmp");
            doBackgroundCollision = Panzerschreck::doBackgroundCollision;
            doPlayerCollision = Panzerschreck::doPlayerCollision;
            break;
        case SHOT_BIGBANG:
            pic = d->sprites->get_shot("bigbang.bmp");
            doBackgroundCollision = BigBang::doBackgroundCollision;
            doPlayerCollision = BigBang::doPlayerCollision;
            break;
        case SHOT_MAX:
            break;
    }
}

// Pretty self-explanatory :3
int doNothing(Shot *s,double delta) { return 0; }
void doIdleInteraction(Shot *s, Player *p) { return; }

// Ouchstuffs
void Gun::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(10);
    shot->killMe = 1;
}

void Missile::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(50);
    shot->killMe = 1;
}

void Laser::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(75);
    shot->killMe = 1;
}

void Cluster::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(50);
    shot->killMe = 1;
}

void BlackHole::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(0);
    shot->killMe = 1;
}

void Badger::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(0);
    shot->killMe = 1;
}

void PlanetMaker::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(0);
    shot->killMe = 1;
}

void Carpet::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(0);
    shot->killMe = 1;
}

void Panzerschreck::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(5);
    shot->killMe = 1;
}

void BigBang::doPlayerCollision(Shot *shot, Player *pl) {
    pl->damage(100);
    shot->killMe = 1;
}

void Gun::doBackgroundCollision(Background *bg, Shot *shot)
{
    // When colliding with the background
    // Do things like spawning new bullets (using DataBank)
    // Or explosions (using Background)
    int posi[2] = {int(shot->g->position[0]), int(shot->g->position[1])};
    double radius = 20.0;
    bg->explodeBackground(posi, shot->g->velocity, radius, 1.75);

    shot->killMe = 1;
}

void Missile::doBackgroundCollision(Background *bg, Shot *shot) {
    int posi[2] = {int(shot->g->position[0]), int(shot->g->position[1])};
    double radius = 40.0;
    bg->explodeBackground(posi, shot->g->velocity, radius, 1.0);

    shot->killMe = 1;
}

void Laser::doBackgroundCollision(Background *bg, Shot *shot) {
    double speed,vx,vy;
    vx = shot->g->velocity[0]; vy = shot->g->velocity[1];
    speed = sqrt(vx*vx+vy*vy);
    bg->explodeFill(int(shot->g->position[0]), int(shot->g->position[1]),
            25.0*(speed/100.0));

    shot->killMe = 1;
}

void Cluster::doBackgroundCollision(Background *bg, Shot *shot) {
    double *vel = shot->g->velocity;
    double *pos = shot->g->position;
    for (int i=0; i<256; i+=8) {
        double newpos[2] = {pos[0]-50+rand()%100, pos[1]-50+rand()%100};
        // double newdir = rand()%256;
        double newvel[2] = {250*cos(i), 250*sin(i)};
        shot->data->makeShot(new Shot(shot->data, SHOT_GUN, newpos,
                    newvel));
    }

    shot->killMe = 1;
}

void BlackHole::doBackgroundCollision(Background *bg, Shot *shot) {
    double pos[2] = {SCREEN_W/2, SCREEN_H/2};
    double vel[2] = {
        (shot->g->position[0]-pos[0])/10,
        (shot->g->position[1]-pos[1])/10};
    for (int i=1; i<16; ++i) {
        double vell[2];
        vell[0] = vel[0]-10+frand()*20;
        vell[1] = vel[1]-10+frand()*20;
        shot->data->makeShot(new Shot(shot->data, SHOT_GUN, pos, vell));
    }

    shot->killMe = 1;
}

void Badger::doBackgroundCollision(Background *bg, Shot *shot) {
    int posi[2] = {int(shot->g->position[0]), int(shot->g->position[1])};
    double vel[2] = {shot->g->velocity[0]*4.5, shot->g->velocity[1]*4.5};

    --shot->life;
    if (shot->life < 0) {
        shot->killMe = 1;
        bg->explodeBackground(posi, vel, 15.0, 1.5);
    }else {
        bg->explodeBackground(posi, vel, 4.5, 7.0);
    }
}

int Badger::doIdle(Shot *shot, double delta)
{
    // Fixed by removing my older fix
    return 0;
}

int Laser::doIdle(Shot *shot, double delta)
{
    double vel[2] = {0.0, 0.0};
    double *pos = shot->g->position;
    shot->data->makeParticle(pos,vel, makecol(255,255,255));
    return 0;
}

void PlanetMaker::doBackgroundCollision(Background *bg, Shot *shot) {
    PlanetMaker::doIdle(shot, 1.0e9);

    shot->killMe = 1;
}

int PlanetMaker::doIdle(Shot *s, double delta)
{
    if (s->flag[0] || delta > 5.0) {
        BITMAP *b;
        b = s->data->sprites->get_random_planet();
        draw_sprite(s->data->getBackground()->getBackground(),b,
                s->g->position[0]-b->w/2, s->g->position[1]-b->h/2);
        s->data->getBackground()->updateAll();

        s->killMe = 1;
        return 1;
    }

    return 0;
}

void PlanetMaker::doInteraction(Shot *s, Player *p)
{
    // Change this to "isActivateButton()" in script? Or something
    if(key[KEY_SPACE]) 
        s->flag[0] = true;
}

void Carpet::doBackgroundCollision(Background *bg, Shot *shot) {
    double vel[2] = {0.0, 100.0};
    for (int i=1; i<64; ++i) {
        double pos[2] = {shot->g->position[0]-32+i, 10.0};
        shot->data->makeShot(new Shot(shot->data, SHOT_BADGER, pos, vel));
    }

    shot->killMe = 1;
}

void Panzerschreck::doBackgroundCollision(Background *bg, Shot *shot)
{
    int posi[2] = {int(shot->g->position[0]), int(shot->g->position[1])};
    double radius = 30.0;
    bg->explodeBackground(posi, shot->g->velocity, radius, 2.0);

    shot->killMe = 1;
}

void BigBang::doBackgroundCollision(Background *bg, Shot *shot)
{
    int posi[2] = {int(shot->g->position[0]), int(shot->g->position[1])};
    double radius = 130.0;
    bg->explodeBackground(posi, shot->g->velocity, radius, 3.0);

    shot->killMe = 1;
}
